from email.quoprimime import quote
import imp
from time import time
from flask import Flask, request
from library import CSULibraryHelper
from qqbot import _bot as bot
from course_list import download_html, Database_helper
import random
import requests
import time
import datetime
import pandas as pd
from urllib.parse import urlencode, quote
import settings
import re
PORT0 = 8207
PORT1 = 5701  # * qqbot


def time_dif_sec(newtime, oldtime):
    d1 = datetime.datetime.strptime(oldtime, '%Y-%m-%d %H:%M:%S')
    d2 = datetime.datetime.strptime(newtime, '%Y-%m-%d %H:%M:%S')
    delta = (d2 - d1).total_seconds()
    return delta


class Bot():
    def __init__(self) -> None:
        pass

    def send_msg(self, uid, msg):
        requests.get(
            url='http://127.0.0.1:{2}/send_private_msg?user_id={0}&message={1}'.format(uid, msg, str(PORT0)))

    def get_friend_list(self):
        r = requests.get(
            url='http://127.0.0.1:{:d}/get_friend_list'.format(PORT0))
        friend_list = r.json()['data']
        return friend_list

    def send_msg_to_all_friends(self, msg):
        friend_list = self.get_friend_list()
        for dat in friend_list:
            uid = dat['user_id']
            nickname = dat['nickname']
            self.send_msg(uid, msg)
            time.sleep(0.5)


class App(Flask):
    def __init__(self, name) -> None:
        super().__init__(__name__)
        self.waiting_list = {}
        self.seat_info = {}
        self.waiting_area = []
        self.db_helper = Database_helper()
        self.userinfo = self.read_userinfo()

    def read_userinfo(self, path='user.csv'):
        userinfo = pd.read_csv('user.csv', usecols=['qq', 'xh', 'passwd'])
        res = {}
        for i in range(len(userinfo)):
            qq = userinfo.iloc[i]['qq']
            xh = userinfo.iloc[i]['xh']
            passwd = userinfo.iloc[i]['passwd']
            res[qq] = {'xh': xh, 'passwd': passwd}
        self.userinfo = res
        return self.userinfo

    def check_userinfo(self, qq):
        print(self.userinfo)
        if qq in self.userinfo.keys():
            return True, self.userinfo[qq]
        else:
            return False, {}

    def update_seat_info(self):
        print('> [INFO] updating seat info')
        self.seat_info = csu.get_seat_info(self.waiting_area)
        return self.seat_info

    def oncall_help(self):
        s = '***使用方法:数字+代号***\n\n\
<1+代号>查询空闲区，如1 X\n\
<2+代号>获取预约链接，如2 X5A\n\
<3+代号+(时间)>蹲守区域，如3 X5\n\
多个区域以空格隔开，如"3 X5A 18:00"\n\n\n\
***代号举例说明***\n\n\
B本部 X新校 T铁道 Y湘雅\n\
B3 本部三楼所有区域\n\
Y3 湘雅新校区三楼\n\
X5A 新校五楼A区'
        return s

    def oncall_search_seatinfo(self, s):
        if s == 'SEARCH':
            msg = '> [HELP] 请输入预定区域(如 X5A / B2)'
            return msg
        else:
            try:
                r = csu.find_free_seat(csu.get_seat_info(csu.process_input(s)))
                res = dict(
                    sorted(r.items(), key=lambda x: x[0], reverse=False))
                if len(res) == 0:
                    return "> [INFO] 该区域没有空座！"
                msg = '> [INFO] 空座信息:\n'
                for k, v in res.items():
                    temp = k[0]+k[2:]
                    msg += '{:s}\t{:d}\n'.format(temp, v['free_seat_num'])
                print(msg)
                return msg
            except:
                msg = '> [HELP] 输入格式错误(如 1 X5A )'
                print(msg)
                return msg
        # else:
        #     msg = '> [HELP] 输入格式错误(如 search / XF5A )'
        #     print(msg)
        #     return msg

    def oncall_bookseat_by_password(self, s):
        # print('> [INFO] 输入了字符串:{:s}'.format(s))
        if s.upper() == 'BOOK':
            return '> [HELP] 输入格式: 2 id password areas\n如:8207202022 password XF5A BF2B'
        else:
            # try:
            s_split = s.split()
            # 解析输入字符串
            username, password, area_temp = s_split[0], s_split[1], s_split[2:]

            csu.set_user_passwd(username, password)
            areas_input_list = csu.process_input(
                ' '.join(area_temp).upper())
            print('> [INFO] 选取的区域: ', areas_input_list)
            # 查询空座信息
            today = True  # 可改进
            area_free_info = csu.find_free_seat(
                csu.get_seat_info(areas_input_list, today=today))
            # 转换所有具有空座的区域的列表
            areas_free_list = list(area_free_info.keys())
            if len(areas_free_list) == 0:
                msg = '> [ERROR] 空座被抢了！'
                print(msg)
                return msg
            # 根据输入的区域顺位选取座位，座位号随机
            chosen_seat = ''
            chosen_seat_id = ''
            segment = ''
            for area in areas_input_list:
                if area not in areas_free_list:
                    pass
                else:
                    chosen_area = area
                    dat = area_free_info[chosen_area]
                    free_seat_num = dat['free_seat_num']
                    chosen_idx = random.randint(0, free_seat_num-1)
                    chosen_seat = dat['true_id'][chosen_idx]
                    chosen_seat_id = dat['free_id'][chosen_idx]
                    segment = dat['segment']
                    break
            # 尝试登陆
            try:
                csu.login()
                print('> [INFO] 登陆成功')
            except:
                msg = '> [ERROR] 登录失败！'
                print(msg)
                return msg
            # 尝试预约
            try:
                respone = csu.book_seat(chosen_seat_id, segment)
                msg = '> [INFO] 选中的座位: {:s}\n> [INFO] 服务器反馈: {:s}'.format(
                    chosen_seat, respone.json()['msg'])
                print(msg)
                # msg = 'debug'
                return msg
            except:
                msg = '> [ERROR] 预约失败！'
                return msg

    def oncall_bookseat_by_link(self, s):
        # print('> [INFO] 输入了字符串:{:s}'.format(s))
        if s.upper() == 'BOOK':
            return '> [HELP] 输入格式: 2 id password areas\n如:8207202022 password XF5A BF2B'
        else:
            areas_input_list = csu.process_input(s)
            area_free_info = csu.find_free_seat(
                csu.get_seat_info(areas_input_list))
            # 转换所有具有空座的区域的列表
            areas_free_list = list(area_free_info.keys())
            if len(areas_free_list) == 0:
                msg = '> [ERROR] 当前区域空位被抢光了！\n尝试输入 “1+代号” 查询其他座位？\n或者尝试输入 “3+代号” 蹲守这些位置？'
                print(msg)
                return msg
                # 根据输入的区域顺位选取座位，座位号随机
            # chosen_seat = ''
            # chosen_seat_id = ''
            chosen_area_id = ''
            chosen_area = ''

            segment = ''
            for area in areas_input_list:
                if area not in areas_free_list:
                    pass
                else:
                    chosen_area = area
                    dat = area_free_info[chosen_area]
                    chosen_area_id = dat['area_id']

                    # free_seat_num = dat['free_seat_num']
                    # chosen_area_id = dat['area_id']
                    # chosen_idx = random.randint(0, free_seat_num-1)
                    # chosen_seat = dat['true_id'][chosen_idx]
                    # chosen_seat_id = dat['free_id'][chosen_idx]
                    segment = dat['segment']
                    break
            date = time.strftime("%Y-%m-%d", time.localtime())
            ts = datetime.datetime.now()
            start_time = ts.time().strftime('%H:%M')
            # book_html_url = 'http://libzw.csu.edu.cn/web/seat3?area={:s}&segment={:s}&day={:s}&startTime=07:30&endTime=22:00'\
            # print((chosen_area_id, str(segment), date, start_time))
            book_html_url = 'http://libzw.csu.edu.cn/web/seat3?area={:s}%26segment={:s}%26day={:s}%26startTime={:s}%26endTime=22:00'\
                .format(chosen_area_id,  str(segment), date, start_time)
            temp = chosen_area[0] + chosen_area[2:]
            msg = '> [INFO] {:s}区预约地址：{:s}'.format(temp, book_html_url)
            print(msg)
            return msg

    def oncall_bookseat_by_link_waiting(self, s, uid):
        s1 = ''
        s2 = ''
        split = s.split()
        if split[-1][0] in '0123456789':
            s1 = ' '.join(split[:-1])
            s2 = split[-1]
        else:
            s1 = s
            s2 = 'now'
        now_date_time_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

        if s2 == 'now':
            reserve_time = now_date_time_str
        else:
            today_str = datetime.datetime.today().strftime(
                '%Y-%m-%d %H:%M:%S')[:10]
            h, m = re.split('[:：/-]', s2)
            time_str = '{:s}:{:s}:00'.format(h, m)
            date_time_str = today_str+' ' + time_str
            if time_dif_sec(date_time_str, now_date_time_str) < 0:
                reserve_time = now_date_time_str
                s2 = 'now'
            else:
                reserve_time = date_time_str
        chosen_area = csu.process_input(s1)
        self.waiting_area.extend(chosen_area)
        self.waiting_area = list(set(self.waiting_area))
        app.waiting_list[uid] = {
            'reserve_time': reserve_time,
            'chosen_area': chosen_area}
        if s2 == 'now':
            msg = '> [INFO] 已经为你蹲守以下区域30分钟：'

        else:
            msg = '> [INFO] 将在{:s}为你蹲守以下区域30分钟：'.format(time_str)
        for area in chosen_area:
            area = area[0]+area[2:]
            msg += area
            msg += '、'
        return msg[:-1]

    def process_waiting_list(self):

        # 最长时间（秒
        TIME_LIMIT = 60*30
        all_seat_info = self.update_seat_info()
        free_seat_info = csu.find_free_seat(all_seat_info)
        free_seat_list = list(free_seat_info.keys())
        # free_seat_list = ['XF5A']
        delete_list = []
        for k, v in self.waiting_list.items():
            uid = k
            chosen_area = v['chosen_area']
            reserve_time = v['reserve_time']

            ts = datetime.datetime.now()
            now_time = ts.strftime('%Y-%m-%d %H:%M:%S')
            dif_sec = time_dif_sec(now_time, reserve_time)
            print(now_time, reserve_time, dif_sec)
            if 0 < dif_sec < 7:
                bot.send_msg(uid, '开始为您蹲守...')
            elif dif_sec < 0:
                continue
            else:
                pass
            # 求交集
            res = list(set(chosen_area).intersection(set(free_seat_list)))
            if len(res) > 0:
                ret, userinfo = self.check_userinfo(uid)
                # print(ret, userinfo)
                if ret:
                    xh = userinfo['xh']
                    passwd = userinfo['passwd']
                    msg = csu.book(xh, passwd, res[0])
                else:
                    bot.send_msg(uid, '> [INFO] 蹲到{:s}区有空位，快去预约！'.format(
                        res[0][0]+res[0][2:]))
                    msg = self.oncall_bookseat_by_link(res[0][0]+res[0][2:])
                bot.send_msg(uid, msg)
                # app.waiting_list.pop(uid)
                delete_list.append(uid)
            else:
                ts = datetime.datetime.now()
                now_time = ts.strftime('%Y-%m-%d %H:%M:%S')
                dif_sec = time_dif_sec(reserve_time, now_time)
                if dif_sec > TIME_LIMIT:
                    delete_list.append(uid)
                    msg = '> [INFO] 蹲守时间超过{:d}秒，所选区域仍未有空位，抱歉orz...可以尝试重新蹲守位置！！！'.format(
                        dif_sec)
                    bot.send_msg(uid, msg)
        is_delete = False
        for uid in delete_list:
            self.waiting_list.pop(uid)
            is_delete = True
        if is_delete:
            self.waiting_area = []
            for k, v in self.waiting_list:
                self.waiting_area.extend(v['chosen_area'])
            self.waiting_area = list(set(self.waiting_area))

    def oncall_get_course_list(self, s):
        if s[0] in '0123456789':
            userid = s
            username = self.db_helper.userid_to_name(userid)
            if username == '':
                return '学号输入错误'
        else:
            username = s
            userid = self.db_helper.name_to_userid(username)
            if userid == '':
                return '姓名输入错误'
        url = 'http://8.134.213.181:9500/#/table?data={:s}&semester=default'.format(
            userid)

        # data = {'type': 'xs0101', 'isview': '0', 'xnxq01id': settings.SEMESTER,
        #         'xs0101id': str(userid),
        #         'xs': username, 'sfFD': '1'}
        # download_html(data)
        # print(url)
        # time.sleep(1)
        return quote(url)

    def process_msg(self, s, uid):
        s = s.strip().upper()
        if s == 'HELP':
            msg = self.oncall_help()
            bot.send_msg(uid, msg)
        else:
            s0 = s[0]
            s = s[1:].strip()
            if s0 == '1':
                # print('> [INFO] SEARCHING')
                msg = self.oncall_search_seatinfo(s)
            elif s0 == '2':
                # print('> [INFO] BOOKING_BY_LINK')
                msg = self.oncall_bookseat_by_link(s)
            elif s0 == '3':
                msg = self.oncall_bookseat_by_link_waiting(s, uid)
            elif s0 == '4':
                msg = self.oncall_get_course_list(s)
            elif s0 == '9':
                msg = self.oncall_bookseat_by_password(s)
            else:
                msg = self.oncall_help()
            bot.send_msg(uid, msg)


'''注意，这里的import api是另一个py文件，下文会提及'''

# app = Flask(__name__)
app = App(__name__)
bot = Bot()
csu = CSULibraryHelper()
'''监听端口，获取QQ信息'''


@app.route('/post_data', methods=["POST"])
def post_data():
    rjson = request.get_json()
    if rjson.get('meta_event_type') == 'heartbeat' and len(app.waiting_list) > 0:
        app.process_waiting_list()
    elif rjson.get('message_type') == 'private':  # 如果是私聊信息
        uid = request.get_json().get('sender').get('user_id')  # 获取信息发送者的 QQ号码
        if str(uid) == '2407156653':
            pass
        else:
            message = request.get_json().get('raw_message')  # 获取原始信息
            app.process_msg(message, uid)
    return 'OK'


@app.route('/course_list',  methods=["GET"])
def course_list():
    userid = request.args.get('userid')
    # username = request.args.get('username')
    text = ''
    with open('/home/EveryClass-collector/course_data/2021-2022-2/{:s}.html'.format(userid)) as f:
        text = f.read()
        f.close()
    return text


if __name__ == '__main__':
    # 此处的 host和 port对应上面 yml文件的设置
    app.run(debug=True, host='0.0.0.0', port=PORT1)
    # onCall_BookSeat_2('BF2B XF7A XF3A XF5A')
